var DyPlugin = {
  install(app, options) {
    // 初始化常用组件
    app.component("QuillEditor", VueQuill.QuillEditor);
    app.component("draggable", vuedraggable);
    app.component("QrcodeVue", QrcodeVue);
    app.component("v-chart", VueECharts);
    app.use(VueViewer.default);
    app.use(JsonExcel);
    // 加载ArcoVue

    app.use(ArcoVue);
    app.use(ArcoVueIcon);
    // 菜单循环
    app.component("MenuTree", {
      template: `
        <template v-for="item in list" :key="item.key">
          <a-sub-menu v-if="item.children&&item.children.length > 0" :key="item.key+'01'">
            <template #icon><component v-if="item.icon" :is="'icon-'+item.icon" size="20"></component></template>
            <template #title>{{item.name}}</template>
            <menu-tree :list="item.children" @on-click="menuClick"></menu-tree> 
          </a-sub-menu>
          <a-menu-item v-else :key="item.key" @click="menuClick(item)">
            <template #icon><component v-if="item.icon"  :is="'icon-'+item.icon" size="20"></component></template>
            {{item.name}}
          </a-menu-item>
        </template>
      `,
      emits: ["onClick"],
      props: {
        list: Array,
      },
      methods: {
        menuClick(e) {
          this.$emit("onClick", e);
        },
      },
    });
    // 媒体选择器
    app.component("uploadSelect", {
      template: `
      <div>
        <div class="upload-select-mask"></div>
        <div class="upload-select">
          <div class="header">
            <div style="flex: 1">素材库</div>
            <i class="close-btn iconfont icon-guanbi1" @click="closeSelected"></i>
          </div>
          <div class="body">
            <!--素材分类 -->
            <div class="left">
              <div class="item-box">
                <div class="item" :class="{ active: currGroup.id == 0 }">
                  <div class="name" @click="changeGroup({ id: 0, name: '全部' })">全部</div>
                  <div class="action" v-if="currGroup.id == 0">
                    <a-dropdown>
                      <i class="iconfont icon-gengduo1"></i>
                      <template #content>
                        <a-doption @click="groupAdd()">添加</a-doption>
                      </template>
                    </a-dropdown>
                  </div>
                </div>
                <div
                  v-for="(item, index) in groupList"
                  :key="index"
                  class="item"
                  :class="{ active: currGroup.id == item.id }"
                >
                  <div class="name" @click="changeGroup(item)">{{ item.name }}</div>
                  <div class="action" v-if="currGroup.id == item.id">
                    <a-dropdown>
                      <i class="iconfont icon-gengduo1"></i>
                      <template #content>
                        <a-doption @click="groupAdd()">添加</a-doption>
                        <a-doption @click="groupSave(item)">编辑</a-doption>
                        <a-doption @click="groupDel(item)">删除</a-doption>
                      </template>
                    </a-dropdown>
                  </div>
                </div>
              </div>
              <!-- 新增/编辑分类 -->
              <div v-if="tempGroup.id >= 0" class="add-group">
                <input v-model="tempGroup.name" type="text" placeholder="输入分组名称" />
                <div style="flex: 1"></div>
                <div class="save-btn" @click="saveGroup">{{ tempGroup.id > 0 ? '保存' : '新增' }}</div>
              </div>
            </div>
            <!--素材 -->
            <div class="right">
              <!--素材操作 -->
              <div class="action">
                <a-space>
                  <a-button type="primary" status="success" :disabled="!selectedId.length" @click="useselected">使用选中</a-button>
                  <a-upload
                    :action="action"
                    :accept="fileAccept"
                    multiple
                    name="file"
                    :headers="headers"
                    :data="uploadData"
                    :limit="100"
                    :show-file-list="false"
                    @success="uploadSuccess"
                    @error="uploadFail"
                  >
                    <a-button v-if="type == 'image'">上传图片</a-button>
                    <a-button v-else-if="type == 'video'">上传视频</a-button>
                    <a-button v-else-if="type == 'audio'">上传音频</a-button>
                    <a-button v-else>上传文件</a-button>
                  </a-upload>
                  <a-button status="danger" :disabled="!selectedId.length" @click="del">删除素材</a-button>
                  <a-select v-model="movecateId" placeholder="移动选中至分组" @change="moveGroup" clearable>
                    <a-option v-for="(item, index) in groupList" :key="index" :value="item.id" :label="item.name"/>
                  </a-select>
                </a-space>
              </div>
              <!--素材列表 -->
              <div class="list-box">
                <div v-for="(item, index) in list" :key="index" class="item" @click="selected(item)">
                  <div class="img" :class="{ active: item.selected }">
                    <img v-if="type == 'image'" :src="item.url" />
                    <i v-else-if="type == 'audio'" class="iconfont icon-wenjianyinpin" style="font-size:40px"></i>
                    <i v-else-if="type == 'video'" class="iconfont icon-a-bianzu72" style="font-size:40px"></i>
                    <i v-else class="iconfont icon-wendang" style="font-size:40px"></i>
                    <div class="selected">
                      <span><i class="iconfont icon-duihao"></i></span>
                    </div>
                  </div>
                  <p>{{ item.real_name }}</p>
                </div>
              </div>
            </div>
          </div>
          <div class="footer">
            <a-pagination :total="total" :page-size="pageSize" show-total show-jumper @change="onChangePagination" />
          </div>
        </div>
      </div>
      `,
      props: {
        modelValue: String,
        multiple: Boolean,
        type: String,
        accept: String,
        limit: {
          type: Number,
          default: 1,
        },
        action: {
          type: String,
          default: "/admin/upload/file",
        },
        listUrl: {
          type: String,
          default: "/admin/upload/file-list",
        },
        delUrl: {
          type: String,
          default: "/admin/upload/file-del",
        },
        groupListUrl: {
          type: String,
          default: "/admin/upload/group-list",
        },
        groupSaveUrl: {
          type: String,
          default: "/admin/upload/group-save",
        },
        groupDelUrl: {
          type: String,
          default: "/admin/upload/group-del",
        },
        groupMoveUrl: {
          type: String,
          default: "/admin/upload/group-move",
        },
        path: {
          type: Boolean,
          default: false,
        },
      },
      emits: ["update:modelValue", "onChange"],
      data() {
        return {
          fileList: [],
          headers: {},
          fileAccept: "",
          uploadData: { groupId: 0, type: "" },
          groupmenusTop: [{ content: "添加", value: 1 }],
          groupmenus: [
            { content: "添加", value: 1 },
            { content: "编辑", value: 2 },
            { content: "删除", value: 3 },
          ],
          currGroup: { id: 0, name: "全部" },
          tempGroup: { id: -1, name: "", type: this.type },
          movecateId: "",
          list: [],
          total: 0,
          pageSize: 18,
          pageNo: 1,
          getMaxTime: 0,
          selectedList: [],
          selectedObj: [],
          selectedId: [],
          fileData: "",
          fieldData: {},
          groupList: [],
        };
      },
      created() {
        if (!this.accept) {
          if (this.type == "image") {
            this.fileAccept = "image/gif, image/jpeg, image/png";
          } else if (this.type == "audio") {
            this.fileAccept = "audio/mpeg";
          } else if (this.type == "video") {
            this.fileAccept = "video/mp4";
          }
        } else {
          this.fileAccept = this.accept;
        }
        this.uploadData.type = this.type;
        this.getFileList();
        this.getGroupList();
      },
      methods: {
        // 获取文件列表
        getFileList() {
          http
            .post(this.listUrl, {
              pageSize: this.pageSize,
              pageNo: this.pageNo,
              groupId: this.currGroup.id,
              type: this.type,
            })
            .then((res) => {
              this.total = res.data.total;
              this.list = [];
              if (res.data.list && res.data.list.length > 0) {
                res.data.list.forEach((item) => {
                  if (this.selectedId.indexOf(item.id) >= 0) {
                    item.selected = true;
                  } else {
                    item.selected = false;
                  }
                  this.list.push(item);
                });
              }
            });
        },
        // 获取分组列表
        getGroupList() {
          http.post(this.groupListUrl, { type: this.type }).then((res) => {
            this.groupList = res.data;
          });
        },
        // 删除
        del() {
          this.$modal.confirm({
            title: "温馨提示",
            content: "确定要删除选中的文件？",
            onOk: () => {
              http.post(this.delUrl, { ids: this.selectedId }).then((res) => {
                this.getFileList();
                this.selectedId = [];
                this.$message.success(res.msg);
              });
            },
          });
        },
        // 切换分组
        changeGroup(item) {
          this.currGroup = item;
          this.tempGroup = { id: -1, name: "", type: this.type };
          this.uploadData.groupId = item.id;
          this.pageNo = 1;
          this.getFileList();
        },
        // 保存分组
        saveGroup() {
          http.post(this.groupSaveUrl, this.tempGroup).then((res) => {
            this.tempGroup = { id: -1, name: "", type: this.type };
            this.getGroupList();
            this.$message.success(res.msg);
          });
        },
        moveGroup(id) {
          this.movecateId = id;
          if (this.selectedId.length === 0) {
            this.$message.error("请选择要移动的素材");
            setTimeout(() => {
              this.movecateId = "";
            }, 500);
          } else {
            http
              .post(this.groupMoveUrl, {
                groupId: id,
                ids: this.selectedId,
              })
              .then((res) => {
                setTimeout(() => {
                  this.movecateId = "";
                }, 500);
                this.selectedList = [];
                this.selectedObj = [];
                this.selectedId = [];
                this.getFileList();
                this.$message.success(res.msg);
              });
          }
        },
        groupAdd() {
          this.tempGroup = { id: 0, name: "", type: this.type };
        },
        groupSave(item) {
          this.tempGroup = JSON.parse(JSON.stringify(item));
        },
        groupDel(item) {
          this.tempGroup = { id: -1, name: "", type: this.type };
          if (!this.currGroup || !this.currGroup.id) {
            this.$message.error("请选择要删除的分类");
          } else {
            this.$modal.confirm({
              title: "温馨提示",
              content: "确定要删除选中的分类？",
              onOk: () => {
                http.post(this.groupDelUrl, { id: item.id }).then((res) => {
                  this.currGroup = { id: 0, name: "全部" };
                  this.getGroupList();
                  this.getFileList();
                  this.$message.success(res.msg);
                });
              },
            });
          }
        },
        // 分页
        onChangePagination(pageNo) {
          this.pageNo = pageNo;
          this.getFileList();
        },
        // 上传失败
        uploadFail() {
          this.$message.error("上传异常");
        },
        // 上传成功
        uploadSuccess(res) {
          if (res.response.code == 1) {
            this.getMaxTime += 1;
            if (this.getMaxTime === 1) {
              setTimeout(() => {
                this.getMaxTime = 0;
                this.getFileList();
              }, 500);
            }
            this.$message.success("上传成功");
          } else {
            this.$message.warning(res.response.msg);
          }
        },
        selected(item) {
          if (item.selected) {
            item.selected = false;
            const index = this.selectedList.indexOf(item.url);
            if (index > -1) {
              this.selectedList.splice(index, 1);
              this.selectedObj.splice(index, 1);
            }
            const index2 = this.selectedId.indexOf(item.id);
            if (index2 > -1) {
              this.selectedId.splice(index, 1);
            }
          } else {
            if (this.multiple) {
              if (this.limit > 1 && this.selectedId.length >= this.limit) {
                this.$message.warning("最多可选择" + this.limit + "个");
                return;
              }
              this.selectedList.push(item.url);
              this.selectedId.push(item.id);
              this.selectedObj.push(item);
              item.selected = true;
            } else {
              this.selectedList = [item.url];
              this.selectedId = [item.id];
              this.selectedObj = [item];
              this.list.forEach((item2) => {
                item2.selected = false;
              });
              item.selected = true;
            }
          }
        },
        useselected() {
          if (this.multiple) {
            let result = this.selectedList.length > 0 ? this.selectedList : [];
            this.$emit("update:modelValue", result);
            this.$emit("onChange", result);
          } else {
            let result = "";
            if (this.path) {
              result =
                this.selectedObj.length > 0 ? this.selectedObj[0].path : "";
            } else {
              result =
                this.selectedObj.length > 0 ? this.selectedObj[0].url : "";
            }
            this.$emit("update:modelValue", result);
            this.$emit("onChange", result);
          }
        },
        closeSelected() {
          this.$emit("update:modelValue", this.multiple ? [] : "");
          this.$emit("onChange", this.multiple ? [] : "");
        },
      },
    });
    // 上传单张图
    app.component("uploadImg", {
      props: {
        modelValue: String,
        name: String,
        action: String,
        accept: String,
        listUrl: String,
        delUrl: String,
        groupListUrl: String,
        groupSaveUrl: String,
        groupDelUrl: String,
        groupMoveUrl: String,
        size: String,
        tip: String,
      },
      emits: ["update:modelValue"],
      template: `
        <div>
            <div class="upload-box">
              <div v-if="modelValue" class="img-list" :style="{ width: size,height:size }"><img :src="modelValue" :style="{ width: size }"><div class="del-btn"><i class="preview-icon iconfont icon-sousuo" @click="preview"></i><span class="line">|</span><i @click="del" class="iconfont icon-shanchu1"></i></div></div>
              <div v-else class="upload-img-btn" :style="{ width: size,height:size }" @click="visibleChoose=true"><i class="add-icon iconfont icon-tianjia"></i></div>
            </div>
            <div class="upload-img-tip">{{tip}}</div>
            <upload-select 
              v-if="visibleChoose" 
              type="image" 
              :action="action" 
              :accept = "accept" 
              :multiple="false" 
              :list-url="listUrl" 
              :del-url="delUrl" 
              :group-list-url="groupListUrl" 
              :group-save-url="groupSaveUrl" 
              :group-del-url="groupDelUrl" 
              :group-move-url="groupMoveUrl" 
              @onChange="selectChange">
            </upload-select>
            <input v-if="name" type="hidden" :name="name" :value="modelValue">
        </div>
      `,
      data() {
        return {
          visibleChoose: false,
        };
      },
      methods: {
        selectChange(e) {
          this.visibleChoose = false;
          if (e) {
            this.$emit("update:modelValue", e);
          }
        },
        del() {
          this.$emit("update:modelValue", "");
        },
        preview() {
          this.$viewerApi({
            images: [this.modelValue],
          });
        },
      },
    });
    // quill富文本编辑器
    app.component("qEditor", {
      template: `
        <div>
          <quill-editor
            v-if="options"
            v-model:content="content"
            theme="snow"
            :options="options"
            content-type="html"
            :style="{ 'height': height,'min-height': minHeight }"
          ></quill-editor>
          <input v-if="name" type="hidden" :name="name" :value="modelValue">
          <upload-select 
          v-if="showImgSelect" 
          type="image" 
          :accept = "accept" 
          multiple
          :action="action" 
          :multiple="false" 
          :list-url="listUrl" 
          :del-url="delUrl" 
          :group-list-url="groupListUrl" 
          :group-save-url="groupSaveUrl" 
          :group-del-url="groupDelUrl" 
          :group-move-url="groupMoveUrl" 
          @onChange="imageSelect">
        </upload-select>
        </div>
      `,
      props: {
        modelValue: String,
        name: String,
        action: String,
        accept: String,
        listUrl: String,
        delUrl: String,
        groupListUrl: String,
        groupSaveUrl: String,
        groupDelUrl: String,
        groupMoveUrl: String,
        height: String,
        minHeight: {
          type: String,
          default: "100px",
        },
      },
      emits: ["update:modelValue"],
      computed: {
        content: {
          get() {
            return this.modelValue;
          },
          set(newValue) {
            this.$emit("update:modelValue", newValue);
          },
        },
      },
      data() {
        return {
          showImgSelect: false,
          options: null,
        };
      },
      created() {
        this.init();
      },
      methods: {
        init() {
          let that = this;
          this.options = {
            height: 500,
            placeholder: "在此处输入内容...",
            modules: {
              toolbar: {
                container: [
                  ["bold", "italic", "underline", "strike"], // toggled buttons
                  ["blockquote", "code-block"],
                  [{ header: 1 }, { header: 2 }], // custom button values
                  [{ list: "ordered" }, { list: "bullet" }],
                  [{ indent: "-1" }, { indent: "+1" }],
                  [{ size: ["small", false, "large", "huge"] }], // custom dropdown

                  [{ color: [] }, { background: [] }], // dropdown with defaults from theme
                  [{ align: [] }],
                  ["link"],
                  ["video"],
                  ["image"],
                  ["clean"],
                ],
                handlers: {
                  image(value) {
                    if (value) {
                      quillThis = this;
                      that.showImgSelect = true;
                    }
                  },
                },
              },
            },
          };
        },
        imageSelect(data) {
          if (data && data.length > 0) {
            data.forEach((element) => {
              const range = quillThis.quill.getSelection(true);
              quillThis.quill.insertEmbed(range.index, "image", element);
              quillThis.quill.setSelection(quillThis.quill.getLength());
            });
          }
          this.showImgSelect = false;
        },
      },
    });
    // 上传多张图
    app.component("uploadImgs", {
      template: `
        <div>
            <draggable :list="list" itemKey="imgs" animation="300" draggable=".img-list" @end="draggableEnd" class="upload-box">
                <template #item="{ element,index }">
                    <div class="img-list">
                      <img :src="element"><div class="del-btn"><i @click="del(index)" class="iconfont icon-shanchu1"></i></div>
                    </div>
                </template>
                <template #footer>
                  <div class="upload-img-btn" @click="visibleChoose=true"><i class="add-icon iconfont icon-tianjia"></i></div>
                </template>
            </draggable>
            <upload-select 
              v-if="visibleChoose" 
              multiple 
              :limit="limit" 
              type="image" 
              :action="action"
              :accept = "accept"  
              :multiple="false" 
              :list-url="listUrl" 
              :del-url="delUrl" 
              :group-list-url="groupListUrl" 
              :group-save-url="groupSaveUrl" 
              :group-del-url="groupDelUrl" 
              :group-move-url="groupMoveUrl" 
              @onChange="selectChange">
            </upload-select>
            <input v-if="name" type="hidden" :name="name" :value="modelValue">
        </div>
      `,
      props: {
        modelValue: String,
        name: String,
        action: String,
        accept: String,
        limit: Number,
        listUrl: String,
        delUrl: String,
        groupListUrl: String,
        groupSaveUrl: String,
        groupDelUrl: String,
        groupMoveUrl: String,
      },
      emits: ["update:modelValue"],
      data() {
        return {
          visibleChoose: false,
          list: [],
        };
      },
      computed: {
        result: {
          get() {
            return this.modelValue ? JSON.parse(this.modelValue) : [];
          },
          set(newValue) {
            this.$emit(
              "update:modelValue",
              newValue ? JSON.stringify(newValue) : ""
            );
          },
        },
      },
      watch: {
        modelValue(newVal, oldVal) {
          if (newVal) {
            this.list = JSON.parse(newVal);
          }
        },
      },
      created() {
        this.list = this.result;
      },
      methods: {
        draggableEnd() {
          this.result = this.list;
        },
        selectChange(e) {
          this.visibleChoose = false;
          if (e && e.length > 0) {
            this.list = this.list.concat(e);
            if (this.limit && this.limit > 0 && this.list.length > this.limit) {
              this.result = this.list.slice(-this.limit);
              this.list = this.result;
            } else {
              this.result = this.list;
            }
          }
        },
        del(index) {
          this.list.splice(index, 1);
          this.result = this.list;
        },
      },
    });
    // 上传多张图预览
    app.component("uploadImgsPreview", {
      template: `
        <div style="display: flex;">
            <draggable :list="list" itemKey="imgs" animation="300" draggable=".img-list" @end="draggableEnd" class="upload-box" style="width:80px;max-height:664px;overflow: auto;">
                <template #item="{ element,index }">
                    <div class="img-list">
                      <img :src="element"><div class="del-btn"><i @click="del(index)" class="iconfont icon-shanchu1"></i></div>
                    </div>
                </template>
                <template #header>
                  <div class="upload-img-btn" @click="visibleChoose=true"><i class="add-icon iconfont icon-tianjia"></i></div>
                </template>
            </draggable>
            <div class="preview-box">
              <div class="titbar"><div class="titbar-w">效果预览</div></div>
              <div class="preview-content">
                <img class="img" v-for="(item,index) in list" :src="item">
              </div>
            </div>
            <upload-select 
              v-if="visibleChoose" 
              multiple 
              :limit="limit" 
              type="image" 
              :action="action"
              :accept = "accept"  
              :multiple="false" 
              :list-url="listUrl" 
              :del-url="delUrl" 
              :group-list-url="groupListUrl" 
              :group-save-url="groupSaveUrl" 
              :group-del-url="groupDelUrl" 
              :group-move-url="groupMoveUrl" 
              @onChange="selectChange">
            </upload-select>
            <input v-if="name" type="hidden" :name="name" :value="modelValue">
        </div>
      `,
      props: {
        modelValue: String,
        name: String,
        action: String,
        accept: String,
        limit: Number,
        listUrl: String,
        delUrl: String,
        groupListUrl: String,
        groupSaveUrl: String,
        groupDelUrl: String,
        groupMoveUrl: String,
      },
      emits: ["update:modelValue"],
      data() {
        return {
          visibleChoose: false,
          list: [],
        };
      },
      computed: {
        result: {
          get() {
            return this.modelValue ? JSON.parse(this.modelValue) : [];
          },
          set(newValue) {
            this.$emit(
              "update:modelValue",
              newValue ? JSON.stringify(newValue) : ""
            );
          },
        },
      },
      watch: {
        modelValue(newVal, oldVal) {
          if (newVal) {
            this.list = JSON.parse(newVal);
          }
        },
      },
      created() {
        this.list = this.result;
      },
      methods: {
        draggableEnd() {
          this.result = this.list;
        },
        selectChange(e) {
          this.visibleChoose = false;
          if (e && e.length > 0) {
            this.list = this.list.concat(e);
            if (this.limit && this.limit > 0 && this.list.length > this.limit) {
              this.result = this.list.slice(-this.limit);
              this.list = this.result;
            } else {
              this.result = this.list;
            }
          }
        },
        del(index) {
          this.list.splice(index, 1);
          this.result = this.list;
        },
      },
    });
    // 上传音频
    app.component("uploadAudio", {
      props: {
        modelValue: String,
        name: String,
        action: String,
        accept: String,
        listUrl: String,
        delUrl: String,
        groupListUrl: String,
        groupSaveUrl: String,
        groupDelUrl: String,
        groupMoveUrl: String,
        width: {
          type: String,
          default: "600px",
        },
        path: {
          type: Boolean,
          default: false,
        },
      },
      emits: ["update:modelValue"],
      template: `
        <div :style="{width:width}">
          <a-input v-model="modelValue" allow-clear readonly @clear="del">
            <template #prepend>
              <div class="select-btn" @click="visibleChoose=true">选择音频</div>
            </template>
            <template v-if="!path && modelValue" #append>
              <div class="select-btn" @click="previrew">预览</div>
            </template>
          </a-input>
          <upload-select 
            v-if="visibleChoose" 
            type="audio" 
            :action="action" 
            :accept = "accept" 
            :multiple="false" 
            :list-url="listUrl" 
            :del-url="delUrl" 
            :group-list-url="groupListUrl" 
            :group-save-url="groupSaveUrl" 
            :group-del-url="groupDelUrl" 
            :group-move-url="groupMoveUrl" 
            @onChange="selectChange">
          </upload-select>
          <input v-if="name" type="hidden" :name="name" :value="modelValue">
        </div>
      `,
      data() {
        return {
          visibleChoose: false,
        };
      },
      methods: {
        selectChange(e) {
          this.visibleChoose = false;
          if (e) {
            this.$emit("update:modelValue", e);
          }
        },
        del() {
          this.$emit("update:modelValue", "");
        },
        previrew() {
          if (this.modelValue && !this.path) {
            window.open(this.modelValue);
          }
        },
      },
    });
    // 上传视频
    app.component("uploadVideo", {
      props: {
        modelValue: String,
        name: String,
        action: String,
        accept: String,
        listUrl: String,
        delUrl: String,
        groupListUrl: String,
        groupSaveUrl: String,
        groupDelUrl: String,
        groupMoveUrl: String,
        width: {
          type: String,
          default: "600px",
        },
        path: {
          type: Boolean,
          default: false,
        },
      },
      emits: ["update:modelValue"],
      template: `
        <div :style="{width:width}">
            <a-input v-model="modelValue" allow-clear readonly @clear="del">
              <template #prepend>
                <div class="select-btn" @click="visibleChoose=true">选择视频</div>
              </template>
              <template v-if="!path && modelValue" #append>
                <div class="select-btn" @click="previrew">预览</div>
              </template>
            </a-input>
            <upload-select 
              v-if="visibleChoose" 
              type="video" 
              :action="action" 
              :accept = "accept" 
              :multiple="false" 
              :list-url="listUrl" 
              :del-url="delUrl" 
              :group-list-url="groupListUrl" 
              :group-save-url="groupSaveUrl" 
              :group-del-url="groupDelUrl" 
              :group-move-url="groupMoveUrl" 
              @onChange="selectChange">
            </upload-select>
            <input v-if="name" type="hidden" :name="name" :value="modelValue">
        </div>
      `,
      data() {
        return {
          visibleChoose: false,
        };
      },
      methods: {
        selectChange(e) {
          this.visibleChoose = false;
          if (e) {
            this.$emit("update:modelValue", e);
          }
        },
        del() {
          this.$emit("update:modelValue", "");
        },
        previrew() {
          if (this.modelValue && !this.path) {
            window.open(this.modelValue);
          }
        },
      },
    });
    // 上传其他文件
    app.component("uploadFile", {
      props: {
        modelValue: String,
        name: String,
        action: String,
        accept: String,
        listUrl: String,
        delUrl: String,
        groupListUrl: String,
        groupSaveUrl: String,
        groupDelUrl: String,
        groupMoveUrl: String,
        width: {
          type: String,
          default: "600px",
        },
        path: {
          type: Boolean,
          default: false,
        },
      },
      emits: ["update:modelValue"],
      template: `
        <div :style="{width:width}">
            <a-input v-model="modelValue" allow-clear readonly @clear="del">
              <template #prepend>
                <div class="select-btn" @click="visibleChoose=true">选择文件</div>
              </template>
              <template v-if="!path && modelValue" #append>
                <div class="select-btn" @click="previrew">预览</div>
              </template>
            </a-input>
            <upload-select 
              v-if="visibleChoose" 
              type="file" 
              :action="action" 
              :accept = "accept" 
              :multiple="false" 
              :list-url="listUrl" 
              :del-url="delUrl" 
              :group-list-url="groupListUrl" 
              :group-save-url="groupSaveUrl" 
              :group-del-url="groupDelUrl" 
              :group-move-url="groupMoveUrl" 
              :path="path" 
              @onChange="selectChange">
            </upload-select>
            <input v-if="name" type="hidden" :name="name" :value="modelValue">
        </div>
      `,
      data() {
        return {
          visibleChoose: false,
        };
      },
      methods: {
        selectChange(e) {
          this.visibleChoose = false;
          if (e) {
            this.$emit("update:modelValue", e);
          }
        },
        del() {
          this.$emit("update:modelValue", "");
        },
        previrew() {
          if (this.modelValue && !this.path) {
            window.open(this.modelValue);
          }
        },
      },
      created() {},
    });
    // 城市选择器
    app.component("citySelect", {
      template: `
        <div style="width:100%">
          <a-cascader v-model="selectPath" :options="list" :pathMode="pathMode" :field-names="fieldNames" allow-search allow-clear @change="change"  @clear="clear" :placeholder="placeholder" />
          <input v-if="name" type="hidden" :name="name" :value="modelValue">
        </div>
      `,
      props: {
        modelValue: String | Array | Number,
        province: String,
        city: String,
        district: String,
        name: String,
        apiUrl: {
          type: String,
          default: "/common/area/list",
        },
        level: {
          type: Number,
          default: 3,
        },
        pathMode: {
          type: Boolean,
          default: true,
        },
        fieldNames: {
          type: Object,
          default: () => {
            return { value: "name", label: "name" };
          },
        },
        placeholder: {
          type: String,
          default: "请选择",
        },
      },
      emits: [
        "update:modelValue",
        "update:province",
        "update:city",
        "update:district",
        "clear",
        "change",
        "selectedData",
      ],
      data() {
        return {
          list: [],
          selectPath: "",
        };
      },
      watch: {
        modelValue(newVal, oldVal) {
          if (newVal) {
            this.selectPath = newVal;
          }
        },
        province(newVal, oldVal) {
          if (newVal) {
            this.selectPath = newVal;
          }
        },
        city(newVal, oldVal) {
          if (newVal) {
            this.selectPath = this.province + "/" + newVal;
          }
        },
        district(newVal, oldVal) {
          if (newVal) {
            this.selectPath = this.province + "/" + this.city + "/" + newVal;
          }
        },
      },
      created() {
        this.getList();
        let selectPath = "";
        if (this.modelValue) {
          selectPath = this.modelValue;
        }
        if (this.province) {
          selectPath = this.province;
        }
        if (this.province && this.city) {
          selectPath = this.province + "/" + this.city;
        }
        if (this.province && this.city && this.district) {
          selectPath = this.province + "/" + this.city + "/" + this.district;
        }
        this.selectPath = selectPath;
        this.$emit("update:modelValue", selectPath);
      },
      mounted() {},
      methods: {
        getList() {
          http.post(this.apiUrl, { level: this.level }).then((res) => {
            this.list = res.data;
          });
        },
        clear() {
          this.$emit("clear", null);
        },
        change(e) {
          this.$emit("change", e);
          let selectPath = "";
          if (e.length > 0) {
            selectPath = e[0];
            this.$emit("update:province", e[0]);
          }
          if (e.length > 1) {
            selectPath = e[0] + "/" + e[1];
            this.$emit("update:city", e[1]);
          }
          if (e.length > 2) {
            selectPath = e[0] + "/" + e[1] + "/" + e[2];
            this.$emit("update:district", e[2]);
          }
          this.$emit("update:modelValue", selectPath);
          if (this.fieldNames.value == "index") {
            let data = [];
            if (e.length > 0) {
              data[0] = this.list[e[0]];
            }
            if (e.length > 1) {
              data[1] = this.list[e[0]].children[e[1]];
            }
            if (e.length > 2) {
              data[2] = this.list[e[0]].children[e[1]].children[e[2]];
            }
            this.$emit("selectedData", data);
          }
        },
      },
    });
    // 腾讯地图地址选择和坐标拾取
    app.component("qqMapGetPoint", {
      template: `
        <div class="input-pick-qq-map">
          <a-input-search v-model="modelValue" placeholder="点击选择位置" allow-clear @clear="clear" button-text="选择位置" search-button @search="open();" />
          <input v-if="name" type="hidden" :name="name" :value="modelValue">
          <div v-if="showModal" class="mask"></div>
          <div class="modal" :style="{top: showModal ? '50%' : -100000}">
            <div class="search">
              <div class="area">
                <city-select
                  :fieldNames="{ value: 'index', label: 'name' }"
                  :level="3"
                  status="1"
                  placeholder="省市区选择"
                  @selectedData="selectedCityData"
                ></city-select>
              </div>
              <div class="keyword">
                <a-select :options="poiList" :loading="loading" placeholder="输入位置名称搜索" allow-clear allow-search :filter-option="false" :field-names="{value: 'id', label: 'title'}" @search="searchPoi" @change="selectedPoi"/>
              </div>
            </div>
            <div class="qqMapGetPoint" :id="'qqMapGetPoint-'+name"></div>
            <div class="action">
              <div v-if="location" style="color:#000;font-size:14px;">当前坐标：{{location ? location : '未选择'}}</div>
              <div v-else style="color:#000;font-size:14px;">当前坐标：<span v-if="lng&&lat">{{lng}},{{lat}}</span><span v-else>未选择</span></div>
              <div style="flex:1;"></div>
              <a-button style="margin-right:10px;" @click="showModal=false">关闭</a-button>
              <a-button type="primary" @click="showModal=false">确定</a-button>
            </div>
          </div>
        </div>
      `,
      props: {
        modelValue: String,
        lat: Number | String,
        lng: Number | String,
        location: String,
        name: String,
        address: String,
        simpleAddress: String,
        detailAddress: String,
        apiUrl: {
          type: String,
          default: "/admin/map/input-tips",
        },
      },
      emits: [
        "update:location",
        "update:lat",
        "update:lng",
        "update:adcode",
        "update:name",
        "update:district",
        "update:address",
        "update:simpleAddress",
        "update:detailAddress",
        "update:modelValue",
        "change",
      ],
      data() {
        return {
          loading: false,
          map: null,
          marker: null,
          showModal: false,
          selectedCity: null,
          poiList: [],
          result: null,
        };
      },
      watch: {
        result(newVal, oldVal) {
          if (newVal && newVal.location) {
            console.log(newVal);
            if (newVal.location.lat) {
              this.$emit(
                "update:location",
                newVal.location.lng + "," + newVal.location.lat
              );
              this.$emit("update:lng", newVal.location.lng);
              this.$emit("update:lat", newVal.location.lat);
              this.$emit(
                "update:modelValue",
                newVal.province + newVal.city + newVal.district + newVal.title
              );
              this.$emit("update:address", newVal.address);
              this.$emit("update:simpleAddress", newVal.title);
              this.$emit("update:detailAddress", newVal.address);
              this.$emit("update:province", newVal.province);
              this.$emit("update:city", newVal.city);
              this.$emit("update:district", newVal.district);
              this.$emit("update:name", newVal.name);
              this.$emit("update:adcode", newVal.adcode);
              this.$emit("change", newVal);
              this.addMarker(newVal.location.lng, newVal.location.lat);
            }
          }
        },
        lng(newVal, oldVal) {
          if (newVal && this.lat && !this.result) {
            this.addMarker(newVal, this.lat);
          }
        },
        location(newVal, oldVal) {
          if (newVal && !this.result) {
            let arr = newVal.split(",");
            if (arr.length == 2) {
              this.addMarker(arr[0], arr[1]);
            }
          }
        },
      },
      created() {},
      mounted() {
        this.mapInit();
      },
      methods: {
        open() {
          this.showModal = true;
          if (this.lng && this.lat) {
            this.addMarker(this.lng, this.lat);
          }
          if (this.location) {
            let arr = this.location.split(",");
            if (arr.length == 2) {
              this.addMarker(arr[0], arr[1]);
            }
          }
        },
        mapInit() {
          //初始化地图
          this.map = new TMap.Map(
            document.getElementById("qqMapGetPoint-" + this.name),
            {
              zoom: 17,
              pitch: 10,
              center: new TMap.LatLng(
                this.lat || 39.953416,
                this.lng || 116.380945
              ),
            }
          );
        },
        addMarker(lng, lat) {
          if (this.marker) {
            this.marker.setMap(null);
          }
          this.marker = new TMap.MultiMarker({
            id: "marker-layer",
            map: this.map,
            styles: {
              marker: new TMap.MarkerStyle({
                width: 20, // 样式宽
                height: 30, // 样式高
                anchor: { x: 10, y: 30 }, // 描点位置
              }),
            },
            geometries: [
              {
                id: "choose1",
                styleId: "marker",
                position: new TMap.LatLng(lat, lng),
                properties: {
                  title: "测试下",
                },
              },
            ],
          });
          this.map.setCenter(new TMap.LatLng(lat, lng));
        },
        selectedCityData(e) {
          if (!e || e.length == 0 || e == undefined) {
            return;
          }
          this.selectedCity = e[e.length - 1];
          this.map.setCenter(
            new TMap.LatLng(
              this.selectedCity.latitude,
              this.selectedCity.longitude
            )
          );
        },
        copy(w) {
          if (copyClipboard(w)) {
            this.$message.success("已复制至系统剪贴板");
          }
        },
        searchPoi(e) {
          if (!this.selectedCity) {
            this.$message.warning("请先选择省/市/区");
            return;
          }
          if (e) {
            this.loading = true;
          }
          http
            .post(this.apiUrl, {
              keyword: e,
              lng: this.selectedCity.longitude,
              lat: this.selectedCity.latitude,
              city: this.selectedCity.name,
              adcode: this.selectedCity.id,
              platform: "qqmap",
            })
            .then((res) => {
              this.poiList = res.data || [];
              this.loading = false;
            })
            .catch(() => {
              this.loading = false;
            });
        },
        selectedPoi(e) {
          this.result = this.poiList.find((el) => {
            return el.id == e;
          });
        },
        clear() {
          this.$emit("update:location", "");
          this.$emit("update:lng", "");
          this.$emit("update:lat", "");
          this.$emit("update:modelValue", "");
          this.$emit("update:address", "");
          this.$emit("update:simpleAddress", "");
          this.$emit("update:detailAddress", "");
          this.$emit("update:district", "");
          this.$emit("update:name", "");
          this.$emit("update:adcode", "");
          this.$emit("change", null);
        },
      },
    });
    // 高德地图地址选择和坐标拾取
    app.component("aMapGetPoint", {
      template: `
        <div class="input-pick-qq-map">
          <a-input-search v-model="modelValue" placeholder="点击选择位置" allow-clear @clear="clear" button-text="选择位置" search-button @search="open();" />
          <input v-if="name" type="hidden" :name="name" :value="modelValue">
          <div v-if="showModal" class="mask"></div>
          <div class="modal" :style="{top: showModal ? '50%' : -100000}">
            <div class="search">
              <div class="area">
                <city-select
                  :fieldNames="{ value: 'index', label: 'name' }"
                  :level="3"
                  status="1"
                  placeholder="省市区选择"
                  @selectedData="selectedCityData"
                ></city-select>
              </div>
              <div class="keyword">
                <a-select :options="poiList" :loading="loading" placeholder="输入位置名称搜索" allow-clear allow-search :filter-option="false" :field-names="{value: 'id', label: 'name'}" @search="searchPoi" @change="selectedPoi"/>
              </div>
            </div>
            <div class="qqMapGetPoint" :id="'aMapGetPoint-'+name"></div>
            <div class="action">
              <div v-if="location" style="color:#000;font-size:14px;">当前坐标：{{location ? location : '未选择'}}</div>
              <div v-else style="color:#000;font-size:14px;">当前坐标：<span v-if="lng&&lat">{{lng}},{{lat}}</span><span v-else>未选择</span></div>
              <div style="flex:1;"></div>
              <a-button style="margin-right:10px;" @click="showModal=false">关闭</a-button>
              <a-button type="primary" @click="showModal=false">确定</a-button>
            </div>
          </div>
        </div>
      `,
      props: {
        modelValue: String,
        lat: Number | String,
        lng: Number | String,
        location: String,
        name: String,
        address: String,
        simpleAddress: String,
        detailAddress: String,
        apiUrl: {
          type: String,
          default: "/admin/map/input-tips",
        },
      },
      emits: [
        "update:location",
        "update:lat",
        "update:lng",
        "update:adcode",
        "update:name",
        "update:district",
        "update:address",
        "update:simpleAddress",
        "update:detailAddress",
        "update:modelValue",
        "change",
      ],
      data() {
        return {
          loading: false,
          map: null,
          marker: null,
          showModal: false,
          selectedCity: null,
          poiList: [],
          result: null,
        };
      },
      watch: {
        result(newVal, oldVal) {
          if (newVal && newVal.location) {
            let arr = newVal.location.split(",");
            if (arr.length == 2) {
              this.$emit("update:location", newVal.location);
              this.$emit("update:lng", arr[0]);
              this.$emit("update:lat", arr[1]);
              this.$emit("update:modelValue", newVal.district + newVal.name);
              this.$emit("update:address", newVal.address);
              this.$emit("update:simpleAddress", newVal.district + newVal.name);
              this.$emit(
                "update:detailAddress",
                newVal.district + newVal.name + newVal.address
              );
              this.$emit("update:province", newVal.province);
              this.$emit("update:city", newVal.city);
              this.$emit("update:district", newVal.district);
              this.$emit("update:name", newVal.name);
              this.$emit("update:adcode", newVal.adcode);
              this.$emit("change", newVal);
              this.addMarker(arr[0], arr[1]);
            }
          }
        },
        lng(newVal, oldVal) {
          if (newVal && this.lat && !this.result) {
            this.addMarker(newVal, this.lat);
          }
        },
        location(newVal, oldVal) {
          if (newVal && !this.result) {
            let arr = newVal.split(",");
            if (arr.length == 2) {
              this.addMarker(arr[0], arr[1]);
            }
          }
        },
      },
      created() {},
      mounted() {
        this.mapInit();
      },
      methods: {
        open() {
          this.showModal = true;
          if (this.lng && this.lat) {
            this.addMarker(this.lng, this.lat);
          }
          if (this.location) {
            let arr = this.location.split(",");
            if (arr.length == 2) {
              this.addMarker(arr[0], arr[1]);
            }
          }
        },
        mapInit() {
          this.map = new AMap.Map("aMapGetPoint-" + this.name, {
            zoom: 17,
          });
          this.map.addControl(new AMap.Scale());
          this.map.addControl(new AMap.ToolBar());
          this.map.addControl(new AMap.ControlBar());
        },
        addMarker(lng, lat) {
          if (this.marker) {
            this.map.remove(this.marker);
          }
          this.marker = new AMap.Marker({
            position: new AMap.LngLat(lng, lat),
          });
          this.map.add(this.marker);
          this.map.setCenter([lng, lat]);
        },
        selectedCityData(e) {
          if (!e || e.length == 0 || e == undefined) {
            return;
          }
          this.selectedCity = e[e.length - 1];
          this.map.setCenter([
            this.selectedCity.longitude,
            this.selectedCity.latitude,
          ]);
        },
        copy(w) {
          if (copyClipboard(w)) {
            this.$message.success("已复制至系统剪贴板");
          }
        },
        searchPoi(e) {
          if (!this.selectedCity) {
            this.$message.warning("请先选择省/市/区");
            return;
          }
          if (e) {
            this.loading = true;
          }
          http
            .post(this.apiUrl, {
              keyword: e,
              lng: this.selectedCity.longitude,
              lat: this.selectedCity.latitude,
              city: this.selectedCity.name,
              adcode: this.selectedCity.id,
              platform: "amap",
            })
            .then((res) => {
              this.poiList = res.data || [];
              this.loading = false;
            })
            .catch(() => {
              this.loading = false;
            });
        },
        selectedPoi(e) {
          this.result = this.poiList.find((el) => {
            return el.id == e;
          });
        },
        clear() {
          this.$emit("update:location", "");
          this.$emit("update:lng", "");
          this.$emit("update:lat", "");
          this.$emit("update:modelValue", "");
          this.$emit("update:address", "");
          this.$emit("update:simpleAddress", "");
          this.$emit("update:detailAddress", "");
          this.$emit("update:district", "");
          this.$emit("update:name", "");
          this.$emit("update:adcode", "");
          this.$emit("change", null);
        },
      },
    });
    // wang编辑器
    app.component("editor", {
      props: {
        /** 编辑器模式 */
        mode: {
          type: String,
          default: "default",
        },
        /** 编辑器默认内容 */
        defaultContent: {
          type: Array,
          default: [],
        },
        defaultHtml: {
          type: String,
          default: "",
        },
        /** 工具栏默认配置 */
        defaultConfigToolbar: {
          type: Object,
          default: () => {
            return {
              insertKeys: {
                index: 100,
                keys: ["imgChoose"],
              },
              hoverbarKeys: {
                "group-image": {
                  menuKeys: [],
                },
              },
              excludeKeys: [
                "blockquote",
                "header1",
                "header2",
                "header3",
                "todo",
                "headerSelect",
                "fontFamily",
                "lineHeight",
                "group-indent",
                "group-video",
                "codeBlock",
              ],
            };
          },
        },
        /** 编辑器默认配置 */
        defaultConfig: {
          type: Object,
          default: {},
        },
        /* 自定义 v-model */
        modelValue: {
          type: String,
          default: "",
        },
        name: String,
        action: String,
        accept: String,
        listUrl: String,
        delUrl: String,
        groupListUrl: String,
        groupSaveUrl: String,
        groupDelUrl: String,
        groupMoveUrl: String,
        height: String,
        minHeight: {
          type: String,
          default: "100px",
        },
      },
      emits: [
        "update:modelValue",
        "onCreated",
        "onChange",
        "onDestroyed",
        "onMaxLength",
        "onFocus",
        "customAlert",
        "customPaste",
        "onBlur",
      ],
      template: `
        <div id="wang-editor—wrapper">
          <div ref="selector" id="wang-toolbar-container"></div>
          <div ref="box" id="wang-editor-container"></div>
        </div>
        <input v-if="name" type="hidden" :name="name" :value="modelValue">
        <upload-select 
          v-if="showImgSelect" 
          type="image" 
          :accept = "accept" 
          multiple
          :action="action" 
          :multiple="false" 
          :list-url="listUrl" 
          :del-url="delUrl" 
          :group-list-url="groupListUrl" 
          :group-save-url="groupSaveUrl" 
          :group-del-url="groupDelUrl" 
          :group-move-url="groupMoveUrl" 
          @onChange="imageSelect">
        </upload-select>
      `,
      data() {
        return {
          showImgSelect: false,
          curValue: "",
          editorRef: Vue.shallowRef,
          toolbar: null,
          editor: null,
        };
      },
      watch: {
        modelValue(newVal, oldVal) {
          if (newVal === this.curValue) return;
          this.setHtml(newVal);
        },
      },
      created() {},
      mounted() {
        this.initEditor();
      },
      methods: {
        //初始化 toolbar
        initToolbar(editor) {
          let that = this;
          const { createToolbar, DomEditor } = window.wangEditor;
          if (!that.$refs.selector) return;
          if (editor == null) {
            throw new Error(
              "Not found instance of Editor when create <Toolbar/> component"
            );
          }
          if (DomEditor.getToolbar(editor)) return; // 不重复创建
          this.toolbar = createToolbar({
            editor,
            selector: that.$refs.selector || "<div></div>",
            mode: that.mode,
            config: that.defaultConfigToolbar,
          });
        },
        initEditor() {
          let that = this;
          class ImgChooseButtonMenu {
            constructor() {
              this.title = "素材库"; // 自定义菜单标题
              //this.iconSvg = `<svg viewBox="0 0 1024 1024"><path d="M959.877 128l0.123 0.123v767.775l-0.123 0.122H64.102l-0.122-0.122V128.123l0.122-0.123h895.775zM960 64H64C28.795 64 0 92.795 0 128v768c0 35.205 28.795 64 64 64h896c35.205 0 64-28.795 64-64V128c0-35.205-28.795-64-64-64zM832 288.01c0 53.023-42.988 96.01-96.01 96.01s-96.01-42.987-96.01-96.01S682.967 192 735.99 192 832 234.988 832 288.01zM896 832H128V704l224.01-384 256 320h64l224.01-192z"></path></svg>`; // 可选
              this.tag = "button";
            }
            // 获取菜单执行时的 value ，用不到则返回空 字符串或 false
            getValue(editor) {
              return "";
            }
            // 菜单是否需要激活（如选中加粗文本，“加粗”菜单会激活），用不到则返回 false
            isActive(editor) {
              return false;
            }
            // 菜单是否需要禁用（如选中 H1 ，“引用”菜单被禁用），用不到则返回 false
            isDisabled(editor) {
              return false;
            }
            // 点击菜单时触发的函数
            exec(editor, value) {
              if (this.isDisabled(editor)) return;
              that.showImgSelect = true;
              editor.restoreSelection();
              //editor.insertText(value); // value 即 this.value(editor) 的返回值
            }
          }
          const { createEditor, Boot } = window.wangEditor;
          Boot.registerMenu({
            key: "imgChoose",
            factory() {
              return new ImgChooseButtonMenu();
            },
          });
          if (!that.$refs.box) return;
          const defaultContent = Vue.toRaw(that.defaultContent);
          this.editor = createEditor({
            selector: that.$refs.box,
            mode: that.mode,
            content: defaultContent || [],
            html: that.defaultHtml || that.modelValue || "",
            config: {
              ...that.defaultConfig,
              MENU_CONF: {
                uploadImage: {
                  server: "/admin/upload/file",
                  fieldName: "file",
                  maxFileSize: 10 * 1024 * 1024,
                  meta: {
                    type: "image",
                    client: "weditor",
                  },
                },
              },
              onCreated(editor) {
                that.editorRef = editor; // 记录 editor 实例
                that.initToolbar(editor);
                that.$emit("onCreated", editor);
              },
              onChange(editor) {
                const editorHtml = editor.getHtml();
                that.curValue = editorHtml; // 记录当前内容
                that.$emit("update:modelValue", editorHtml); // 触发 v-model 值变化
                that.$emit("onChange", editor);
              },
              onDestroyed(editor) {
                that.$emit("onDestroyed", editor);
              },
              onMaxLength(editor) {
                that.$emit("onMaxLength", editor);
              },
              onFocus(editor) {
                that.$emit("onFocus", editor);
              },
              onBlur(editor) {
                that.$emit("onBlur", editor);
              },
              customAlert(info, type) {
                that.$emit("customAlert", info, type);
              },
              customPaste: (editor, event) => {
                let res;
                that.$emit("customPaste", editor, event, (val) => {
                  res = val;
                });
                return res;
              },
            },
          });
        },
        setHtml(newHtml) {
          const editor = this.editorRef;
          if (editor == null) return;
          editor.setHtml(newHtml);
        },
        imageSelect(data) {
          this.editor.restoreSelection();
          if (data && data.length > 0) {
            console.log(data);
            data.forEach((element) => {
              this.editor.dangerouslyInsertHtml("<img src='" + element + "'/>");
            });
          }
          this.showImgSelect = false;
        },
      },
    });
  },
};
